#include "utilities.h"

void* connect_f(void* ptr)
{
	int sock1;  
	struct hostent *host;
	struct sockaddr_in server_addr1;
	unsigned int portnumber = (unsigned int)ptr ;
	struct addrinfo hints, *servinfo, *p;
	int rv;
	int bytes_recieved;
	struct timeval readtime;
	hello_msg t1;
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	
	if ((rv = getaddrinfo(hostname,port_recieve_str, &hints, &servinfo)) != 0) 
	{
		if(printFlag==1)
		{
			fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
		}
		pthread_exit(0);
	}
	
	host = gethostbyname("nunki.usc.edu");
	server_addr1.sin_family = AF_INET;     
	server_addr1.sin_port = htons(portnumber);   
	server_addr1.sin_addr = *((struct in_addr *)host->h_addr);
	memset(&(server_addr1.sin_zero), 0, sizeof server_addr1.sin_zero);
	while(1)
	{
		if(dieChild)
		{
			close(sock1);
			pthread_exit(NULL);
		}
		pthread_mutex_lock(&maplock);
		if(myMap.find(portnumber)->second.connectflag==1)
		{
			if(printFlag==1)
			{
				printf("Connection established at recieve\n");
			}
			close(sock1);
			pthread_mutex_unlock(&maplock);
			if(printFlag==1)
			{
				printf("Connect Thread Close\n");
			}
			pthread_exit(NULL);
		}
		pthread_mutex_unlock(&maplock);
		// loop through all the results and connect to the first we can
		for(p = servinfo; p != NULL; p = p->ai_next) 
		{
			if ((sock1 = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1) 
			{
				//perror("client: socket");
				continue;
			}
			break;
		}
		if (connect(sock1, (struct sockaddr *)&server_addr1,sizeof(struct sockaddr)) == -1) 
		{
			if(!isBeacon && minNeighFlag)
			{
				close(sock1);
				pthread_exit(NULL);
			}
			int timeCount = 0;
			while(1)
			{
				timeCount = initMap["Retry"].asDouble;
				while(timeCount)
				{
					if(dieChild)
					{
						close(sock1);
						pthread_exit(NULL);
					}
					usleep(1000000);
					timeCount--;
				}
			}
		}
		else
		{
			if(printFlag==1)
			{
				printf("Connection established at connect\n");
			}
			pthread_mutex_lock(&maplock);
			if(myMap.find(portnumber)->second.connectflag==0)
			{
				beaconmap temp1;
				temp1.socknumber = sock1;
				temp1.connectflag = 1;
				myMap[portnumber] = temp1;
			}
			else
			{
				close(sock1);
				pthread_mutex_unlock(&maplock);
				if(printFlag==1)
				{
					printf("Connect Thread Close\n");
				}
				pthread_exit(NULL);
			}

			pthread_mutex_unlock(&maplock);	
			char buf[512];
			struct timeval writetime;
			gettimeofday(&writetime,NULL);
			fillMsgHdrBuffer(myHello.header, buf);
			memcpy(&(buf[27]),&(myHello.hostport),sizeof(uint16_t));
			memcpy(&(buf[29]),myHello.hostname,myHello.header.datalength - sizeof(uint16_t));
			write(sock1,buf,27+sizeof(myHello.hostport)+strlen(myHello.hostname));
			listBuffStruct lbtemp;
			lbtemp.logtype = 1;
			memset(lbtemp.listBuff, '\0', sizeof buf);
			memcpy(lbtemp.listBuff, buf,sizeof buf);
			lbtemp.datalength = 27+sizeof(myHello.hostport)+strlen(myHello.hostname);
			lbtemp.portNumber = portnumber;
			write_to_log(lbtemp,lbtemp.logtype,writetime);
			bytes_recieved = read(sock1,buf,sizeof buf);
			if(bytes_recieved==0)
			{
				if(printFlag==1)
				{
					printf("Error in message recieved\n");
				}
				close(sock1);
				if(printFlag==1)
				{
					printf("Connect Thread Close\n");
				}
				pthread_exit(NULL);
			}
			fillMsgHdrStructure(t1.header, buf);
			memcpy(&(t1.hostport),&(buf[27]),sizeof(uint16_t));
			memcpy(t1.hostname,&(buf[29]),myHello.header.datalength - sizeof(uint16_t));
			gettimeofday(&readtime,NULL);
			lbtemp.logtype = 0;
			memset(lbtemp.listBuff, '\0', bytes_recieved);
			memcpy(lbtemp.listBuff, buf,bytes_recieved);
			lbtemp.datalength = bytes_recieved;
			lbtemp.portNumber = portnumber;
			write_to_log(lbtemp,lbtemp.logtype,readtime);
			if(printFlag==1)
			{
				printf("Message Type is %x\nMessage UOID is ",t1.header.msgtype);
			}
			for(int i=0;i<20;i++)
			{
			uint8_t x = t1.header.uoid[i];
			if(printFlag==1)
			{
				printf("%02x",x);
			}
			}
			
			struct timeval readtime;
			gettimeofday(&readtime,NULL);
			if(printFlag==1)
			{
				printf("\nMessage TTL is %d\nMessage Length is %d\n",t1.header.timetolive,t1.header.datalength);
				printf("The connecting beacon node portnumber : %d and hostname : %s \n",t1.hostport, t1.hostname);
			}
			break;
		}
	}
	
	pthread_t readThr;
	pthread_t writeThr;
	
	allTimers tempTimer;
	tempTimer.keepAliveTime = 0;
	tempTimer.joinTime = 0;
	myTimers[portnumber] = tempTimer;
	
	writeListData listDataStr;
	list<listBuffStruct> writeList;
	writeStruct wrStruct;
	wrStruct.portNumber = portnumber;
	wrStruct.sock = sock1;
	listDataStr.response = writeList;
	listDataStr.dieflag = false;
	memset(listDataStr.hostname,'\0',512);
	memcpy(listDataStr.hostname,t1.hostname,strlen(t1.hostname));
	pthread_mutex_lock(&writeMapMutex);
	writeMap[portnumber] = listDataStr;
	pthread_mutex_unlock(&writeMapMutex);
	pthread_create(&readThr, NULL, readfun, (void *)&wrStruct);
	pthread_create(&writeThr, NULL, writefun, (void *)&wrStruct);
	if(!isBeacon && minNeighFlag)
	{
		minNeighCount++;
	}
	pthread_exit(NULL);
}
